#include "wrapping_integers.hh"
#include <iostream>

// Dummy implementation of a 32-bit wrapping integer

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

constexpr uint64_t SeqCount = uint64_t(1) << 32;
constexpr uint64_t HalfBallPark = uint64_t(1) << 31;

//! Transform an "absolute" 64-bit sequence number (zero-indexed) into a WrappingInt32
//! \param n The input absolute 64-bit sequence number
//! \param isn The initial sequence number
WrappingInt32 wrap(uint64_t n, WrappingInt32 isn) {
    return WrappingInt32((n + isn.raw_value()) % SeqCount);
}

//! Transform a WrappingInt32 into an "absolute" 64-bit sequence number (zero-indexed)
//! \param n The relative sequence number
//! \param isn The initial sequence number
//! \param checkpoint A recent absolute 64-bit sequence number
//! \returns the 64-bit sequence number that wraps to `n` and is closest to `checkpoint`
//!
//! \note Each of the two streams of the TCP connection has its own ISN. One stream
//! runs from the local TCPSender to the remote TCPReceiver and has one ISN,
//! and the other stream runs from the remote TCPSender to the local TCPReceiver and
//! has a different ISN.
uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) {
    uint64_t absolute_seqno = n.raw_value() >= isn.raw_value()? static_cast<uint64_t>(n.raw_value()) - isn.raw_value()
                              : (static_cast<uint64_t>(n.raw_value()) + SeqCount - isn.raw_value());

    uint64_t sub = (checkpoint > absolute_seqno? checkpoint - absolute_seqno : absolute_seqno - checkpoint);
    uint64_t nsc = sub / SeqCount;
    nsc += (sub % SeqCount) > HalfBallPark;
    uint64_t bytes = nsc * SeqCount;
    // cout << (n.raw_value() >= isn.raw_value()) << ", " << n << " - " << isn << ", " << sub << ", " << 
    // nsc << ", " << bytes << endl;
    if(checkpoint > absolute_seqno){
        if(UINT64_MAX - absolute_seqno < bytes){
            absolute_seqno = bytes - (UINT64_MAX - absolute_seqno) - 1;
        }else{
            absolute_seqno += bytes;
        }
    }else{
        if(absolute_seqno < bytes){
            absolute_seqno = UINT32_MAX - (bytes - absolute_seqno - 1);
        }else
            absolute_seqno -= bytes;
    }

    return absolute_seqno;
//
//    uint64_t left = absolute_seqno >= HalfBallPark? absolute_seqno - HalfBallPark : 0;
//    if(checkpoint < left){
//        // 推左半边
//        while(absolute_seqno - HalfBallPark > checkpoint) {
//            if(absolute_seqno < SeqCount)
//                break;
//            absolute_seqno -= SeqCount;
//        }
//    }else if(checkpoint > absolute_seqno){
//        // 推右半边
//        while(absolute_seqno + HalfBallPark < checkpoint) {
//            if(UINT64_MAX - absolute_seqno < SeqCount)
//                break;
//            absolute_seqno += SeqCount;
//        }
//    }
//
//    return absolute_seqno;
}
